"ui";
let config = require("config.js");
ui.layout(
  <vertical>
    <text textStyle="bold" textSize="26sp" gravity="center" marginTop="26" marginBottom="20">
      下载码云仓库
    </text>
    <vertical margin="8">
      <horizontal>
        <text w="0" layout_weight="3" textSize="20">
          仓库链接
        </text>
        <input
          id="repoUrl"
          w="0"
          layout_weight="7"
          type="text"
          hint="https://gitee.com/yourname/obsidiandata.git"
          text=""
        />
      </horizontal>
      <horizontal>
        <text w="0" layout_weight="3" textSize="20">
          指定文件夹
        </text>
        <input
          id="obsidianDataFilePath"
          w="0"
          layout_weight="7"
          type="text"
          hint="/sdcard/obsidianData"
          text=""
        />
      </horizontal>
      <horizontal h="wrap_content">
        <text id="fileSizeTextView" w="0" layout_weight="3">
          文件大小限制(MB)
        </text>
        <input id="fileSizeLimit" w="0" layout_weight="7" inputType="number" hint="10" />
      </horizontal>
      <button marginTop="20" id="rwpermission">
        请打开文件和媒体读写权限
      </button>
      <button marginTop="20" id="start">
        开始下载
      </button>
    </vertical>
  </vertical>
);

if (android.os.Environment.isExternalStorageManager()) {
  log("已授权 所有文件管理权限");
} else {
  log("未授权 所有文件管理权限");
  let intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
  let packageName = context.getPackageName();
  intent.setData(android.net.Uri.parse("package:" + packageName));
  activity.startActivityForResult(intent, 123);
}

let fileSizeTextView = ui.fileSizeTextView;
fileSizeTextView.setSingleLine(true);
fileSizeTextView.setEllipsize(android.text.TextUtils.TruncateAt.END);
fileSizeTextView.setHorizontallyScrolling(true);

let sdPath = files.getSdcardPath(); // /storage/emulated/0
log(sdPath);
let finalObsidianDataFilePath;
let finalFileSizeLimit;
let downloadedCount = 0;
let totalFilesToDownloadCount = 0;
console
  .build({
    size: [0.8, 0.3],
    title: "HELLO WORLD",
    titleTextSize: 18,
    contentTextSize: 16,
    backgroundColor: "deep-orange-900",
    titleBackgroundAlpha: 0.8,
    contentBackgroundAlpha: 0.5,
    exitOnClose: 100,
  })
  .show();

let dw = device.width;
let dh = device.height;
console.setPosition(dw * 0.1, dh * 0.5);
/* -------------------------------------------------------------------------- */
ui.rwpermission.click(() => {
  let intent = new Intent();
  intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
  let uri = android.net.Uri.fromParts("package", context.getPackageName(), null);
  intent.setData(uri);
  app.startActivity(intent);
});

ui.start.click(() => {
  let repoUrl = ui.repoUrl.text();
  if (!/https:\/\/gitee\.com\/[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+\.git/.test(repoUrl)) {
    toastLog("仓库链接错误");
    return;
  }
  log("仓库链接正确");
  let obsidianDataFilePath = ui.obsidianDataFilePath.text();
  if (!/\/sdcard\/.+/.test(obsidianDataFilePath)) {
    toastLog("指定文件夹错误");
    return;
  }
  log("指定文件夹正确");

  if (android.os.Environment.isExternalStorageManager()) {
    log("已授权 所有文件管理权限");
    let sdPath = files.getSdcardPath(); // /storage/emulated/0
    log(sdPath);

    obsidianDataFilePath = sdPath + obsidianDataFilePath.replace("/sdcard", "");
    console.log("🚀 ~ obsidianDataFilePath:", obsidianDataFilePath);
    if (!obsidianDataFilePath.endsWith("/")) {
      obsidianDataFilePath += "/";
    }
    log("obsidianDataFilePath = " + obsidianDataFilePath);
    files.ensureDir(obsidianDataFilePath);
    finalObsidianDataFilePath = obsidianDataFilePath;
  } else {
    toastLog("未授权 所有文件管理权限");
    let intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
    let packageName = context.getPackageName();
    intent.setData(android.net.Uri.parse("package:" + packageName));
    activity.startActivityForResult(intent, 123);
    return;
  }

  let fileSizeLimit = ui.fileSizeLimit.text();
  if (!fileSizeLimit) {
    fileSizeLimit = config.fileSizeLimit;
  }
  if (!/^[0-9]+$/.test(fileSizeLimit)) {
    toastLog("文件大小限制错误");
    return;
  }
  fileSizeLimit = +fileSizeLimit;
  if (fileSizeLimit == 0) {
    toastLog("文件大小限制错误");
    return;
  }
  log("文件大小限制正确");
  finalFileSizeLimit = fileSizeLimit;
  work(repoUrl);
});
function work(repoUrl) {
  log(`repoUrl: ${repoUrl}`);
  threads.start(function () {
    let filesToDownload = getFilesToDownload(repoUrl);
    // filesToDownload = filesToDownload.splice(0, 100);
    // log(filesToDownload);
    log("最终要下载的文件数量 filesToDownload.length = " + filesToDownload.length);
    totalFilesToDownloadCount = filesToDownload.length;
    batchDownload(filesToDownload);
  });
}

function batchDownload(files) {
  let total = files.length;
  let downloaded = 0;
  let pos = 0;
  // 批次控制
  function nextBatch() {
    let batch = files.slice(pos, pos + config.CONCURRENT_LIMIT);
    pos += config.CONCURRENT_LIMIT;
    let promises = batch.map(downloadFile);
    return Promise.allSettled(promises).then((results) => {
      results.forEach((result) => console.log(result));
      downloaded += batch.length;
      if (downloaded < total) {
        return nextBatch();
      }
    });
  }

  // 完成提示
  return new Promise((resolve) => {
    nextBatch().then(() => {
      console.log("所有文件下载完成");
      console.setTitle("all done");
      resolve();
    });
  });
}

function downloadFile(file) {
  // 文件下载逻辑
  // 方便测试, 用setTimeout模拟
  let downloadPromise = new Promise((resolve, reject) => {
    console.log(`开始下载: ${file.path}`);
    let url = file.url + "?access_token=" + config.token;
    console.log("🚀 ~ downloadPromise ~ url:", url);
    http.get(
      url,
      {
        headers: {
          "Content-Type": "application/json;charset=UTF-8",
        },
      },
      (res, err) => {
        if (err) {
          // 下载失败
          log(err);
          warn(`下载异常: ${file.path}`);
          reject(`下载异常: ${file.path}`);
        } else {
          log(`下载完成: ${file.path}`);
          // 下载成功
          let base64Content = res.body.json().content;
          log("开始解码base64内容");
          let bytes = android.util.Base64.decode(base64Content, 0);
          log("结束解码base64内容");
          let filePath = finalObsidianDataFilePath + file.path;
          console.log("🚀 ~ downloadPromise ~ filePath:", filePath);
          files.ensureDir(filePath);
          log(`开始保存文件: ${filePath}`);
          files.writeBytes(filePath, bytes);
          log(`结束保存文件: ${filePath}`);
          downloadedCount += 1;
          console.setTitle(`进度: ${downloadedCount}/${totalFilesToDownloadCount}`);
          resolve(`下载完成: ${filePath}`);
        }
      }
    );
  });
  return downloadPromise;
}

function getFilesToDownload(repoUrl) {
  let remoteAllFileInfo = getRemoteAllFileInfo(repoUrl);
  let len = remoteAllFileInfo.length;
  let filesToDownload = [];
  for (let i = 0; i < len; i++) {
    console.setTitle(`仓库文件对比 ${i + 1}/${len}`);
    let remoteFileInfo = remoteAllFileInfo[i];
    if (remoteFileInfo.type == "blob") {
      if (remoteFileInfo.size > finalFileSizeLimit * 1024 * 1024) {
        log(`文件 ${remoteFileInfo.path} 太大, 超过 ${finalFileSizeLimit} MB, 不下载`);
        continue;
      }
      let filePath = finalObsidianDataFilePath + remoteFileInfo.path;
      if (!files.exists(filePath)) {
        filesToDownload.push(remoteFileInfo);
        continue;
      }
      let fileSize = getFileSize(filePath);
      if (fileSize != remoteFileInfo.size) {
        filesToDownload.push(remoteFileInfo);
      }
    }
  }
  console.setTitle(`仓库文件对比 完成`);
  log(`remoteAllFileInfo.length = ${remoteAllFileInfo.length}`);
  log(`filesToDownload.length = ${filesToDownload.length}`);
  return filesToDownload;
}
function getFileSize(filePath) {
  filePath = files.path(filePath);
  let file = new java.io.RandomAccessFile(filePath, "r");
  let channel = file.getChannel();
  let mappedBuf = channel.map(java.nio.channels.FileChannel.MapMode.READ_ONLY, 0, channel.size());
  let size = mappedBuf.limit();
  return size;
}
function getRemoteAllFileInfo(repoUrl) {
  const owner = getOwner(repoUrl);
  const repo = getRepo(repoUrl);
  const token = config.token;
  log(`owner: ${owner}\n repo: ${repo}`);
  // 构造请求URL
  const apiUrl = `https://gitee.com/api/v5/repos/${owner}/${repo}/git/trees/master?access_token=${token}&recursive=1`;
  log(apiUrl);
  console.time("获取所有文件信息消耗时间");
  var r = http.get(apiUrl, {
    headers: {
      "Content-Type": "application/json;charset=UTF-8",
    },
  });
  log("code = " + r.statusCode);
  let tree = r.body.json().tree;
  log(tree.length);
  console.timeEnd("获取所有文件信息消耗时间");
  return tree;
}

function getOwner(repoUrl) {
  const pattern = /gitee\.com\/([^/]+)\/([^/]+)\.git/;
  return repoUrl.match(pattern)[1];
}
function getRepo(repoUrl) {
  const pattern = /gitee\.com\/([^/]+)\/([^/]+)\.git/;
  return repoUrl.match(pattern)[2];
}
